﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Xml;
using System.Drawing;
using ArgusLib.Xml;
using ArgusLib.Fractals;
using ArgusLib.Collections;
using ArgusLib.Drawing.Formats;

namespace Fraktalysator
{
	partial class MainForm
	{
		const string RootNameSaveFile = "FraktalysatorSaveFile";
		const string NameFractal = "Fractal";
		const string NameRenderer = "Renderer";
		static readonly PNG.ChunkType ChunkType = new PNG.ChunkType("fxMl");

		private void miHelpHomepage_Click(object sender, EventArgs e)
		{
			System.Diagnostics.Process.Start(HomepageAdress);
		}

		private string SaveToString()
		{
			StringBuilder sBuilder = new StringBuilder();
			XmlWriterSettings settings = new XmlWriterSettings();
			settings.Indent = true;
			XmlWriter xmlWriter = XmlWriter.Create(sBuilder, settings);
			using (Serializer seri = new Serializer(xmlWriter, RootNameSaveFile))
			{
				seri.Serialize(NameFractal, this.Fractal);
				seri.Serialize(NameRenderer, this.formRendererParameter.GetRenderer());
			}
			return sBuilder.ToString();
		}

		private byte[] SaveToBytes()
		{
			using (MemoryStream ms = new MemoryStream())
			{
				XmlWriterSettings settings = new XmlWriterSettings();
				settings.Indent = true;
				XmlWriter xmlWriter = XmlWriter.Create(ms, settings);
				using (Serializer seri = new Serializer(xmlWriter, RootNameSaveFile))
				{
					seri.Serialize(NameFractal, this.Fractal);
					seri.Serialize(NameRenderer, this.formRendererParameter.GetRenderer());
				}
				ms.Seek(0, SeekOrigin.Begin);
				byte[] data = new byte[ms.Length];
				ms.Read(data, 0, data.Length);
				return data;
			}
		}

		private bool LoadFromString(string xml, bool addToHistory)
		{
			IFractal fractal = null;
			IRenderer renderer = null;

			using (StringReader stringReader = new StringReader(xml))
			{
				XmlReader xmlReader = XmlReader.Create(stringReader);
				using (Deserializer deseri = new Deserializer(xmlReader))
				{
					if (deseri.RootName == RootNameSaveFile)
					{
						ListPair<string, object> objs = deseri.DeserializeAll();
						int i = objs.List1.IndexOf(NameFractal);
						if (i > -1)
							fractal = objs.List2[i] as IFractal;
						i = objs.List1.IndexOf(NameRenderer);
						if (i > -1)
							renderer = objs.List2[i] as IRenderer;
					}
				}
			}

			if (fractal == null || renderer == null)
			{
				return false;
			}
			else
			{
				this.Fractal = fractal;
				this.formFractalParameter.SelectFractal(fractal);
				this.formRendererParameter.InitializeRendererList(fractal);
				this.formRendererParameter.SelectRenderer(renderer);
				this.StartCalculation(addToHistory);
				return true;
			}
		}

		private bool LoadFromBytes(byte[] xml)
		{
			IFractal fractal = null;
			IRenderer renderer = null;

			using (MemoryStream ms = new MemoryStream(xml))
			{
				XmlReader xmlReader = XmlReader.Create(ms);
				using (Deserializer deseri = new Deserializer(xmlReader))
				{
					if (deseri.RootName == RootNameSaveFile)
					{
						ListPair<string, object> objs = deseri.DeserializeAll();
						int i = objs.List1.IndexOf(NameFractal);
						if (i > -1)
							fractal = objs.List2[i] as IFractal;
						i = objs.List1.IndexOf(NameRenderer);
						if (i > -1)
							renderer = objs.List2[i] as IRenderer;
					}
				}
			}

			if (fractal == null || renderer == null)
			{
				return false;
			}
			else
			{
				this.Fractal = fractal;
				this.formFractalParameter.SelectFractal(fractal);
				this.formRendererParameter.InitializeRendererList(fractal);
				this.formRendererParameter.SelectRenderer(renderer);
				return true;
			}
		}

		private void miFileSave_Click(object sender, EventArgs e)
		{
			if (this.saveFileDialog.ShowDialog() != System.Windows.Forms.DialogResult.OK)
				return;

			string path = this.saveFileDialog.FileName;
			if (path.EndsWith(".xml") == true)
			{
				using (StreamWriter writer = new StreamWriter(path))
				{
					string xml = this.SaveToString();
					writer.Write(xml);
				}
			}
			else if (path.EndsWith(".png") == true)
			{
				if (this.formImage.Image != null)
				{
					using (Stream file = this.saveFileDialog.OpenFile())
					{
						this.formImage.Image.Save(file, System.Drawing.Imaging.ImageFormat.Png);
						file.Seek(0, SeekOrigin.Begin);
						ArgusLib.Drawing.Formats.PNG png = ArgusLib.Drawing.Formats.PNG.Open(file);
						Byte[] xml = this.SaveToBytes();
						png.WriteChunk(ChunkType, xml);
					}
				}
			}
			else
			{
				throw new Exception("Invalid Filename.");
			}

			this.tslStatusMessage.Text = Localization.Text.Message_FileSaved + ' ' + path;
		}

		private void miFileOpen_Click(object sender, EventArgs e)
		{
			if (this.openFileDialog.ShowDialog() != System.Windows.Forms.DialogResult.OK)
				return;

			bool valid = false;
			if (this.openFileDialog.FileName.EndsWith(".xml") == true)
			{
				string xml;
				using (StreamReader reader = new StreamReader(this.openFileDialog.FileName))
				{
					xml = reader.ReadToEnd();
				}

				if (this.LoadFromString(xml, true) == true)
				{
					this.tslStatusMessage.Text = Localization.Text.Message_FileLoaded + ' ' + this.openFileDialog.FileName;
					valid = true;
				}
			}
			else if (this.openFileDialog.FileName.EndsWith(".png") == true)
			{
				using (Stream file = this.openFileDialog.OpenFile())
				{
					PNG png = PNG.Open(file);
					byte[] xml = png.ReadChunk(ChunkType, out valid);
					if (valid == true && this.LoadFromBytes(xml) == true)
					{
						this.formImage.Magnification = 1;
						this.formImage.Image = Image.FromFile(this.openFileDialog.FileName);
						this.formImage.ImageSize = this.formImage.Image.Size;
						this.tslStatusMessage.Text = Localization.Text.Message_FileLoaded + ' ' + this.openFileDialog.FileName;
						valid = true;
					}
					else
					{
						valid = false;
					}
				}
			}

			if (valid == false)
			{
				MessageBox.Show(Localization.Text.MessageBox_InvalidSaveFile, Localization.Text.MessageBox_InvalidSaveFileCaption);
			}
		}

		private void miEditBack_Click(object sender, EventArgs e)
		{
			this.history.Pop();
			string xml = this.history.Peek();
			if (this.history.Count < 2)
			{
				this.miEditBack.Enabled = false;
				this.tsEditBack.Enabled = false;
			}
			this.LoadFromString(xml, false);
		}

		private void miHelpAbout_Click(object sender, EventArgs e)
		{
			Forms.AboutForm aboutForm = new Forms.AboutForm();
			aboutForm.ShowDialog();
		}

		private void miHelpUpdates_CheckedChanged(object sender, EventArgs e)
		{
			if (this.miHelpUpdates.Checked == false)
				return;
			if (this.IsLoaded == false)
				return;

			UpdateChecker.GetUpdates(new Action<UpdateInfo[]>((infos) =>
			{
				if (infos != null && infos.Length > 0)
				{
					this.Invoke(new Action(() =>
						{
							Forms.UpdateInfoBox.ShowUpdates(infos);
						}));
				}
			}));
		}

		private void miFilePrintscreen_Click(object sender, EventArgs e)
		{
			using (Bitmap bitmap = new Bitmap(this.Width, this.Height))
			{
				this.DrawToBitmap(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height));

				SaveFileDialog sfd = new SaveFileDialog();
				sfd.FileName = this.saveFileDialog.FileName;
				sfd.Filter = Localization.Text.SaveFileDialog_FilterImagePng + "|*.png";
				sfd.FilterIndex = 0;

				if (sfd.ShowDialog() != System.Windows.Forms.DialogResult.OK)
					return;

				bitmap.Save(sfd.FileName);
			}
		}
	}
}
